use std::borrow::Cow;

use conn_port::ConnPort;
use tauri::{command, Window};
use tokio::sync::Mutex;

use crate::error::AppErr;

mod conn_port;

static PORT: Mutex<Option<ConnPort>> = Mutex::const_new(None);

#[command]
pub fn available_ports() -> Result<Box<[String]>, AppErr> {
    let ports: Vec<tokio_serial::SerialPortInfo> = tokio_serial::available_ports()?;
    Ok(ports.into_iter().map(|item| item.port_name).collect())
}

#[command]
pub async fn open(name: String, baud_rate: u32, window: Window) -> Result<(), AppErr> {
    let mut lock = PORT.lock().await;

    match &*lock {
        Some(v) => v.close(),
        None => {}
    };
    *lock = Some(ConnPort::new(&name, baud_rate, window)?);

    Ok(())
}

#[command]
pub async fn close() -> Result<(), AppErr> {
    let mut lock = PORT.lock().await;
    if let Some(v) = &*lock {
        v.close();
    }
    *lock = None;
    Ok(())
}

#[command]
pub async fn is_open() -> bool {
    PORT.lock().await.is_some()
}

#[command]
pub async fn write(buf: Box<[u8]>) -> Result<(), AppErr> {
    if let Some(port) = &mut *PORT.lock().await {
        port.write(&buf).await?;
        Ok(())
    } else {
        Err(AppErr::Other(Cow::Borrowed("串口没有打开")))
    }
}
